﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Grafos;

namespace GrafosTestUnit {
    /// <summary>
    /// Testa a classe MatrizDeAdjacencia e os métodos relacionados nas classes Grafo e GrafoPonderado
    /// </summary>
    [TestClass]
    public class TesteMatrizDeAdjacencia {
        /// <summary>
        /// Verifica se o grafo gerado a partir de uma matriz de adjacência é correto
        /// </summary>
        /// <remarks>
        /// Processo:
        /// Define uma matriz de adjacência como segue:
        /// {false, true, false, true, false, false, false, false, false, false},
        /// {true, false, true, false, false, false, false, false, false, false},
        /// {false, true, false, true, true, false, false, false, false, false},
        /// {true, false, true, false, false, false, false, false, false, false},
        /// {false, false, true, false, false, true, true, true, false, false},
        /// {false, false, false, false, true, false, true, false, false, false},
        /// {false, false, false, false, true, true, false, false, false, false},
        /// {false, false, false, false, true, false, false, false, true, true},
        /// {false, false, false, false, false, false, false, true, false, true},
        /// {false, false, false, false, false, false, false, true, true, false}
        /// Define G como um grafo a partir de tal matriz, nomeando seus vértices A..J
        /// Verifica-se:
        /// G possui 12 arestas
        /// G possui 10 vértices
        /// G possui as arestas: A-B, A-D, B-C, C-D, C-E, E-F, E-G, E-H, F-G, H-I, H-J, I-J
        /// </remarks>
        [TestMethod]
        public void GerarDeMatriz() {
            Grafo g;
            string[] nomes;
            bool[,] matriz;

            nomes = new string[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" };
            matriz = new bool[,] {
                {false, true, false, true, false, false, false, false, false, false},
                {true, false, true, false, false, false, false, false, false, false},
                {false, true, false, true, true, false, false, false, false, false},
                {true, false, true, false, false, false, false, false, false, false},
                {false, false, true, false, false, true, true, true, false, false},
                {false, false, false, false, true, false, true, false, false, false},
                {false, false, false, false, true, true, false, false, false, false},
                {false, false, false, false, true, false, false, false, true, true},
                {false, false, false, false, false, false, false, true, false, true},
                {false, false, false, false, false, false, false, true, true, false}
            };

            g = Grafo.GerarDeMatrizDeAdjacencia(nomes, matriz);

            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("A"), g.BuscarVértice("B")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("A"), g.BuscarVértice("D")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("B"), g.BuscarVértice("C")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("C"), g.BuscarVértice("D")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("C"), g.BuscarVértice("E")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("E"), g.BuscarVértice("F")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("E"), g.BuscarVértice("G")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("E"), g.BuscarVértice("H")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("F"), g.BuscarVértice("G")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("H"), g.BuscarVértice("I")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("H"), g.BuscarVértice("J")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("I"), g.BuscarVértice("J")));
            Assert.AreEqual(12, g.QuantidadeArestas);
            Assert.AreEqual(10, g.QuantidadeVértices);
        }

        /// <summary>
        /// Verifica se o grafo gerado a partir de uma matriz de adjacência é correto
        /// </summary>
        /// <remarks>
        /// Define uma matriz de adjacência como segue:
        /// {0, 12, 0, 10, 0, 0, 0, 0, 0, 0},
        /// {12, 0, 5, 0, 0, 0, 0, 0, 0, 0},
        /// {0, 5, 0, 7, 4, 0, 0, 0, 0, 0},
        /// {10, 0, 7, 0, 0, 0, 0, 0, 0, 0},
        /// {0, 0, 4, 0, 0, 12, 3, 1, 0, 0},
        /// {0, 0, 0, 0, 12, 0, 12, 0, 0, 0},
        /// {0, 0, 0, 0, 3, 12, 0, 0, 0, 0},
        /// {0, 0, 0, 0, 1, 0, 0, 0, 6, 3},
        /// {0, 0, 0, 0, 0, 0, 0, 6, 0, 4},
        /// {0, 0, 0, 0, 0, 0, 0, 3, 4, 0}
        /// Define G como um grafo a partir de tal matriz, nomeando seus vértices A..J
        /// Verifica-se:
        /// G possui 12 arestas
        /// G possui 10 vértices
        /// O peso total das arestas de G é 79
        /// G possui as arestas A-B, A-D, B-C, C-D, C-E, E-F, E-G, E-H, F-G, H-I, H-J, I-J
        /// </remarks>
        [TestMethod]
        public void GerarPonderadoDeMatriz() {
            GrafoPonderado g;
            string[] nomes;
            float[,] matriz;

            nomes = new string[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J" };
            matriz = new float[,] {
                {0, 12, 0, 10, 0, 0, 0, 0, 0, 0},
                {12, 0, 5, 0, 0, 0, 0, 0, 0, 0},
                {0, 5, 0, 7, 4, 0, 0, 0, 0, 0},
                {10, 0, 7, 0, 0, 0, 0, 0, 0, 0},
                {0, 0, 4, 0, 0, 12, 3, 1, 0, 0},
                {0, 0, 0, 0, 12, 0, 12, 0, 0, 0},
                {0, 0, 0, 0, 3, 12, 0, 0, 0, 0},
                {0, 0, 0, 0, 1, 0, 0, 0, 6, 3},
                {0, 0, 0, 0, 0, 0, 0, 6, 0, 4},
                {0, 0, 0, 0, 0, 0, 0, 3, 4, 0}
            };

            g = GrafoPonderado.GerarDeMatrizDeAdjacencia(nomes, matriz);

            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("A"), g.BuscarVértice("B")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("A"), g.BuscarVértice("D")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("B"), g.BuscarVértice("C")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("C"), g.BuscarVértice("D")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("C"), g.BuscarVértice("E")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("E"), g.BuscarVértice("F")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("E"), g.BuscarVértice("G")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("E"), g.BuscarVértice("H")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("F"), g.BuscarVértice("G")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("H"), g.BuscarVértice("I")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("H"), g.BuscarVértice("J")));
            Assert.IsTrue(g.PossuiArestaParalela(g.BuscarVértice("I"), g.BuscarVértice("J")));
            Assert.AreEqual(12, g.QuantidadeArestas);
            Assert.AreEqual(10, g.QuantidadeVértices);
            Assert.AreEqual(79, g.PesoTotal());
        }

        /// <summary>
        /// Lê um grafo do disco para a memória
        /// </summary>
        /// <remarks>
        /// Processo:
        /// Carrega a matriz de adjacência para os arquivos "cidades_nomes.txt" e "cidades.txt"
        /// Gera o grafo G a partir de tal matriz
        /// Verifica-se:
        /// G possui 3 vétices
        /// G possui 3 arestas
        /// G possui as arestas:
        /// São Carlos-Ibaté
        /// Ibaté-Araraquara
        /// São Carlos-Araraquara
        /// </remarks>
        [TestMethod]
        [DeploymentItem("cidades.txt")]
        [DeploymentItem("cidades_nomes.txt")]
        public void LerGrafoDoDisco() {
            MatrizDeAdjacencia mda;
            Grafo g;

            mda = new MatrizDeAdjacencia();
            mda.Carregar("cidades_nomes.txt", "cidades.txt");

            g = Grafo.GerarDeMatrizDeAdjacencia(mda.GetNomes(), mda.GetMatriz());

            Assert.AreEqual(3, g.QuantidadeVértices);
            Assert.AreEqual(3, g.QuantidadeArestas);
            Assert.IsTrue(g.PossuiArestaParalela("São Carlos", "Ibaté"));
            Assert.IsTrue(g.PossuiArestaParalela("Ibaté", "Araraquara"));
            Assert.IsTrue(g.PossuiArestaParalela("São Carlos", "Araraquara"));
        }

        /// <summary>
        /// Lê um grafo ponderado do disco para a memória
        /// </summary>
        /// <remarks>
        /// Processo:
        /// Carrega a matriz de adjacência ponderada para os arquivos "cidades_nomes.txt" e "cidades.txt"
        /// Gera o grafo ponderado G a partir de tal matriz
        /// Verifica-se:
        /// G possui 3 vértices
        /// G possui 3 arestas
        /// G possui as arestas com os seguintes pesos:
        /// São Carlos-Ibaté (1)
        /// Ibaté-Araraquara (1)
        /// São Carlos-Araraquara (2)
        /// </remarks>
        [TestMethod]
        [DeploymentItem("cidades.txt")]
        [DeploymentItem("cidades_nomes.txt")]
        public void LerGrafoPonderadoDoDisco() {
            MatrizDeAdjacencia mda;
            GrafoPonderado g;

            mda = new MatrizDeAdjacencia();
            mda.Ponderada = true;
            mda.Carregar("cidades_nomes.txt", "cidades.txt");

            g = GrafoPonderado.GerarDeMatrizDeAdjacencia(mda.GetNomes(), mda.GetMatrizPonderada());

            Assert.AreEqual(3, g.QuantidadeVértices);
            Assert.AreEqual(3, g.QuantidadeArestas);
            Assert.IsTrue(g.PossuiArestaParalela("São Carlos", "Ibaté"));
            Assert.IsTrue(g.PossuiArestaParalela("Ibaté", "Araraquara"));
            Assert.IsTrue(g.PossuiArestaParalela("São Carlos", "Araraquara"));
            Assert.AreEqual(2, ((ArestaPonderada)g.BuscarVértice("São Carlos").ProcurarAresta(g.BuscarVértice("Araraquara"))).Valor);
            Assert.AreEqual(1, ((ArestaPonderada)g.BuscarVértice("Ibaté").ProcurarAresta(g.BuscarVértice("Araraquara"))).Valor);
            Assert.AreEqual(1, ((ArestaPonderada)g.BuscarVértice("Ibaté").ProcurarAresta(g.BuscarVértice("São Carlos"))).Valor);
        }

        /// <summary>
        /// Testa a geração de matriz de adjacência
        /// </summary>
        /// <remarks>
        /// Processo:
        /// Definem-se os gabaritos {"A", "B", "C"} e { {false, true, true}, {true, false, true}, {true, true, false} }
        /// Cria o grafo G com vértices "A", "B" e "C", e arestas A-B, A-C e B-C
        /// Gera a lista de nomes e a matriz de adjacência de G
        /// Compara-se todos os elementos gerados com seus respectivos gabaritos
        /// </remarks>
        [TestMethod]
        public void GerarMatriz() {
            Grafo g;
            string[] nome;
            bool[,] matriz;
            int i, j;
            string[] gabaritoNome;
            bool[,] gabaritoMatriz;

            gabaritoNome = new string[] { "A", "B", "C" };
            gabaritoMatriz = new bool[,] {
                {false, true, true},
                {true, false, true},
                {true, true, false}
            };

            g = new Grafo();
            g.AdicionarVértice("A", "B", "C");
            g.AdicionarAresta("A", "B");
            g.AdicionarAresta("A", "C");
            g.AdicionarAresta("B", "C");

            g.GerarMatrizDeAdjacencia(out nome, out matriz);

            for (i = 0; i < nome.Length; i++) {
                Assert.AreEqual(gabaritoNome[i], nome[i]);
            }
            for (i = 0; i < matriz.GetLength(0); i++) {
                for (j = 0; j < matriz.GetLength(1); j++) {
                    Assert.AreEqual(gabaritoMatriz[i, j], matriz[i, j]);
                }
            }
        }

        /// <summary>
        /// Testa a geração de matriz de adjacência
        /// </summary>
        /// <remarks>
        /// Processo:
        /// Definem-se os gabaritos {"A", "B", "C"} e { {0, 5, 10}, {5, 0, 8}, {10, 8, 0} }
        /// Cria o grafo G com vértices "A", "B" e "C", e arestas A-B (5), A-C (10) e B-C (8)
        /// Gera a lista de nomes e a matriz de adjacência de G
        /// Compara-se todos os elementos gerados com seus respectivos gabaritos
        /// </remarks>
        [TestMethod]
        public void GerarMatrizPonderado() {
            GrafoPonderado g;
            string[] nome;
            float[,] matriz;
            int i, j;
            string[] gabaritoNome;
            float[,] gabaritoMatriz;

            gabaritoNome = new string[] { "A", "B", "C" };
            gabaritoMatriz = new float[,] {
                {0, 5, 10},
                {5, 0, 8},
                {10, 8, 0}
            };

            g = new GrafoPonderado();
            g.AdicionarVértice("A", "B", "C");
            g.AdicionarAresta("A", "B", 5);
            g.AdicionarAresta("A", "C", 10);
            g.AdicionarAresta("B", "C", 8);

            g.GerarMatrizDeAdjacencia(out nome, out matriz);

            for (i = 0; i < nome.Length; i++) {
                Assert.AreEqual(gabaritoNome[i], nome[i]);
            }
            for (i = 0; i < matriz.GetLength(0); i++) {
                for (j = 0; j < matriz.GetLength(1); j++) {
                    Assert.AreEqual(gabaritoMatriz[i, j], matriz[i, j]);
                }
            }
        }
    }
}
